package com.gopay.bis.web.controller.mtpay;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.gopay.remote.cashier.bis.CashierBgNotifyRemoteService;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.servlet.ModelAndView;

import com.gopay.bis.common.util.BisPayCheckUtils;
import com.gopay.bis.domain.order.OrderInfo;
import com.gopay.bis.service.bank.BankOrderService;
import com.gopay.common.Result;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.domain.bank.BankOrder;
import com.gopay.common.domain.bank.BaseMessage;
import com.gopay.common.domain.bank.external.BisExternalMessage;
import com.gopay.common.domain.proccode.ProcCodeInfo;
import com.gopay.common.proccode.DicProcCodeService;
import com.gopay.common.util.HttpTransport;
import com.gopay.remote.bank.BankInteractRemoteService;
import com.gopay.remote.bank.MtPayInteractRemoteService;

/**
 * 银行回应基类
 * 
 * @BankResBase.java
 * @author 
 */
public abstract class MtPayBankResBase {
	
	private static Log logger = LogFactory.getLog(MtPayBankResBase.class);

	@Resource(name = "bisConfig")
	protected Map<String, String> bisConfig;

	@Resource(name = "mtPaybankInteractService")
	private MtPayInteractRemoteService mtPaybankInteractService;

	@Resource(name = "bisInteractExternalService")
	BankInteractRemoteService bisInteractExternalService;
	
	@Resource(name = "dicProcCodeService")
	private DicProcCodeService dicProcCodeService;

	@Resource(name = "notifyCashier")
	private HttpTransport notifyCashier;

	@Resource(name = "cashierBgNotifyRemoteService")
	private CashierBgNotifyRemoteService cashierBgNotifyRemoteService;
	
	@Resource(name = "bankOrderService")
	private BankOrderService bankOrderService;
	/**
	 * 构建支付类对象
	 * 
	 * @param orderId
	 * @return
	 */
	protected abstract BaseMessage buildMessage(HttpServletRequest request);

	/**
	 * 构建返回收银台参数
	 * 
	 * @param request
	 * @return
	 */
	protected abstract OrderInfo buildOrderInfo(HttpServletRequest request,Result result);

	/**
	 * 验证返回参数
	 * 
	 * @param request
	 * @return
	 */
	protected abstract boolean checkParameters(HttpServletRequest request);

	/**
	 * 银行通知入口
	 * 
	 * @param request
	 * @param response
	 * @return
	 */
	protected ModelAndView execute(HttpServletRequest request,HttpServletResponse response) {
		// 打印请求参数
		this.displayRequestParameters(request, logger);
		//校验参数
		boolean isCheck = checkParameters(request);
		// 前台通知地址
		String notifyUrl = bisConfig.get("BIS.CLIENT.NOTIFY.CASHIER.BANK.RES");
		String viewName = bisConfig.get("BIS.NOTIFY.CASHIER.FORWARD.FAIL");
		ModelAndView model = new ModelAndView();
		model.setViewName(viewName);
		try {
			if(isCheck){
				OrderInfo orderInfo = null;
				// 验签
				Result result = mtPaybankInteractService.bankBack(buildMessage(request));
				// 构建发往收银台的参数
				orderInfo = buildOrderInfo(request, result);
				if (result.isSuccess()) {
					if ((Boolean) result.getDefaultModel()) {
						Map<String, String> param  = (Map<String, String>)result.getModel("isNotifyCashier");
						String gopayOrderID = param.get("orderId");
						List bankOrderList = bankOrderService.getBankOrdersByGopayOrderId(gopayOrderID);
						 BankOrder bankOrder =null;
						 if(bankOrderList!=null && bankOrderList.size()>0){
							 bankOrder = (BankOrder)bankOrderList.get(0);
						 }
						//根据订单号判断如果为外部平台的话走外部平台返回签名流程
						if(BisPayCheckUtils.checkExternalOrderID(gopayOrderID)){
							BisExternalMessage bisMessage = new BisExternalMessage();
							bisMessage.setOrderId(gopayOrderID);
							bisMessage.setAmount(new BigDecimal(param.get("amt")));
							bisMessage.setBank(bankOrder.getBankCode());
							if(param.get("payStatus").equals("00")){
								bisMessage.setTradeState("1");
							}else{
								bisMessage.setTradeState("-1");
							}
							Result bisResult  = bisInteractExternalService.bankBack(bisMessage);
							//如果银行返回成功并且签名成功设置成功页面
							if(param.get("payStatus").equals("00") && bisResult.isSuccess()){
								String redirectUrl = (String)bisResult.getModel("redirectUrl");
								viewName = "redirect:"+redirectUrl;
							}
							model.setViewName(viewName);
							logger.error(orderInfo);
							logger.error(notifyUrl);
							return model;
						}else{
							//通知cashier入账
							String isFront = param.get("isFront");
							if(isFront.equals("false")){
								/*notifyCashier.submit(param);*/ //生产优化10期 lx 2017-9-30 16:23:37
								cashierBgNotifyRemoteService.callBgNotify(param);
							}							
							// 设置成功页面
							viewName = bisConfig.get("BIS.NOTIFY.CASHIER.FORWARD");
							// 通知银行
							if (orderInfo.getIsNotify()) {
								notifyBank(response, orderInfo);
							}
						}
					} else if (!(Boolean) result.getDefaultModel()) {
						// 验签失败
						ProcCodeInfo procCodeInfo = dicProcCodeService.getProcCodeInfo(ProcCodeConstants.PROC_CODE_100E6040);
						orderInfo.setRetCode(ProcCodeConstants.PROC_CODE_100E6040);
						orderInfo.setRetMsg(procCodeInfo.getMessage());
					}
					else if (StringUtils.equals(ProcCodeConstants.PROC_CODE_100E6026,result.getResultCode())) {
						// 重复验签也返回成功页面，由收银台统一跳转
						viewName = bisConfig.get("BIS.NOTIFY.CASHIER.FORWARD");
						// 通知银行
						if (orderInfo.getIsNotify()) {
							notifyBank(response, orderInfo);
						}
					}
				} else {
					// 验签异常
					ProcCodeInfo procCodeInfo = dicProcCodeService.getProcCodeInfo(result.getResultCode());
					orderInfo.setRetCode(result.getResultCode());
					orderInfo.setRetMsg(procCodeInfo.getMessage());
				}
				model.setViewName(viewName);
				model.addObject("notifyUrl", notifyUrl);
				model.addObject("orderInfo", orderInfo);
				logger.error(orderInfo);
				logger.error(notifyUrl);
			}else{
				model.addObject("errorCode", ProcCodeConstants.PROC_CODE_100E7023);
				model.addObject("errorMsg", "bank back notify parameters is null");
			}
		} catch (Exception e) {
			logger.error("BankResBase error：", e);
			model.addObject("errorCode", ProcCodeConstants.PROC_CODE_100F1002);
			model.addObject("errorMsg", e.getMessage());
		}
		return model;
	}

	/**
	 * 通知银行处理结果
	 * 
	 * @param HttpServletResponse
	 * @param OrderInfo
	 * @return boolean
	 */
	protected boolean notifyBank(HttpServletResponse response,OrderInfo orderInfo) {
		StringBuffer paramters = new StringBuffer();
		paramters.append((String) bisConfig.get("BANK.PAY.CALLBACK.URL")).append("?");
		paramters.append("orderId=").append(orderInfo.getOrderId());
		paramters.append("&payStatus=").append(orderInfo.getPayStatus());
		paramters.append("&amt=").append(orderInfo.getAmt());
		paramters.append("&cardType=").append(orderInfo.getCardType());
		paramters.append("&retCode=").append(orderInfo.getRetCode());
		paramters.append("&bankName=").append(orderInfo.getBankName());
		String notifyMsg = paramters.toString();
		ServletOutputStream out = null;
		try {
			if ("umpay".equals(orderInfo.getBankName())) {
				notifyMsg = orderInfo.getRetMsg();
			}
			response.setContentType("text/html;charset=GBK");
			logger.error("notifyBank " + orderInfo.getBankName()+ " send content: \n[" + notifyMsg + "]");
			out = response.getOutputStream();
			out.print(notifyMsg);
			out.flush();
			return true;
		} catch (IOException e) {
			logger.error("notifyBank" + orderInfo.getBankName()+ "send error: ", e);
			return false;
		} finally {
			if (out != null) {
				try {
					out.close();
				} catch (IOException e) {
					logger.error("notifyBank close error: ", e);
					return false;
				}
			}
		}
	}

	/**
	 * 输出请求参数
	 * 
	 * @param request
	 */
	@SuppressWarnings("rawtypes")
	protected void displayRequestParameters(HttpServletRequest request,Log logger) {
		for (Enumeration enumeration = request.getParameterNames(); enumeration.hasMoreElements();) {
			String eleName = (String) enumeration.nextElement();
			String eleValue = request.getParameter(eleName);
			if (logger != null) {
				logger.error("map key: [" + eleName + "]，value: [" + eleValue+ "]");
			}
		}
	}

}
